﻿using System;
using System.Timers;
using Timer = System.Timers.Timer;

namespace QueuingSimulation
{
    public class Server
    {

        #region Events

        public event EventHandler<ServerStateChangeEventArgs> StateChange;

        protected virtual void OnStateChange(ServerStateChangeEventArgs e)
        {
            EventHandler<ServerStateChangeEventArgs> handler = StateChange;
            if (handler != null) handler(this, e);
        }

        //public event EventHandler<TransactionErrorArgs> TransactionError;

        #endregion

        #region Properties

        public string Name { get; set; }
        public int Priority { get; set; }
        public int MinServiceTime { get; set; }
        public int MaxServiceTime { get; set; }
        public ServerState ServerState { get; set; }
        public double TimerInterval
        {
            get { return _timerInterval; }
            set
            {
                _timerInterval = value;
                Timer = new Timer(value);
                Timer.Elapsed += TimerOnElapsed;
            }
        }

        public Timer Timer { get; set; }

        #endregion

        #region Private Members

        private int _timerValue;
        private int _lastEndTime;
        private readonly Random _random = new Random();
        private Client _client;
        private int _busyTime;
        private int _freeTime;
        private double _timerInterval;

        #endregion

        public void Reset()
        {
            _busyTime = 0;
            _freeTime = 0;
            _timerValue = 0;
            _lastEndTime = 0;
            Timer.Stop();
        }

        private void TimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
        {
            if (ServerState == ServerState.Busy) _busyTime++; else _freeTime++;

            if (_lastEndTime != 0 && _lastEndTime == _timerValue)
            {
                Console.WriteLine(Name + " work finished." + " at: " + _timerValue);
                ServerState = ServerState.Free;
                var args = new ServerStateChangeEventArgs
                {
                    ServerState = ServerState.Free,
                    Time = _timerValue,
                    Client = _client
                };
                OnStateChange(args);
            }
            _timerValue++;
        }

        public int GetTotalBusyTime()
        {
            return _busyTime;
        }
        public int GetTotalFreeTime()
        {
            return _freeTime;
        }

        public void StarWork(Client client)
        {
            var workDuration = _random.Next(MinServiceTime, MaxServiceTime);
            _lastEndTime = workDuration + _timerValue;
            ServerState = ServerState.Busy;
            _client = client;
            _client.ServiceDurationTime = workDuration;
            _client.ExitTime = workDuration + _client.ServiceStartTime;
            _client.WaitInQueueTime = _client.ServiceStartTime - _client.EnterTime;
            _client.TotalWaitingTime = _client.ExitTime - _client.EnterTime;
            var args = new ServerStateChangeEventArgs
            {
                ServerState = ServerState.Busy,
                Time = _timerValue,
                Client = client
            };
            OnStateChange(args);
            Console.WriteLine(Name + " work start." + " at: " + _timerValue);
        }
    }
}
